#pragma once

#include "Socket.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"
#include "Common.hpp"
#include <memory>
#include <unordered_map>
#include "Connection.hpp"
#include "Epoller.hpp"

using namespace SocketModule;
#define BUFF_SIZE 32

class Reactor
{
private:
    bool ConnectionExist(int sockfd)
    {
        auto iter = _connections.find(sockfd);
        if (iter == _connections.end())
            return false;
        else
            return true;
    }

    void PrintConnection()
    {
        std::cout << "_connections[]: ";
        for (auto &conn : _connections)
        {
            std::cout << conn.second->GetFd() << " ";
        }
        std::cout << std::endl;
    }

    int LoopOnce(int timeout)
    {
        int n = _epoller_ptr->WaitEvent(_buff, BUFF_SIZE, timeout);
        return n;
    }
    void Dispacther(int n)
    {
        for (int i = 0; i < n; i++)
        {
            int sockfd = _buff[i].data.fd;
            int revents = _buff[i].events;
            // 将revents错误情况都转化成IO错误，统一处理
            if (revents & EPOLLERR) // 文件描述符错误
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLHUP) // 连接关闭
                revents |= (EPOLLIN | EPOLLOUT);

            if (revents & EPOLLIN)
            {
                if (ConnectionExist(sockfd))
                {
                    _connections[sockfd]->Recver();
                }
            }
            if (revents & EPOLLOUT)
            {
                if (ConnectionExist(sockfd))
                    _connections[sockfd]->Sender();
            }
        }
    }

public:
    Reactor()
        : _epoller_ptr(std::make_unique<Epoller>()),
          _isrunning(false)
    {
    }

    void Loop()
    {
        _isrunning = true;
        int timeout = -1;
        while (_isrunning)
        {
            PrintConnection();
            int n = LoopOnce(timeout);
            Dispacther(n);
        }
        _isrunning = false;
    }

    void AddConnection(const std::shared_ptr<Connection> &conn)
    {
        // 0.检查conn对应的fd是否存在
        if (ConnectionExist(conn->GetFd()))
            return;

        // 1.添加事件和fd到内核中
        int fd = conn->GetFd();
        uint32_t events = conn->GetEvents();
        _epoller_ptr->ADDEvent(fd, events);

        // 2.conn添加回指指针
        conn->SetOwner(this);

        // 3.添加到_connections中
        _connections[fd] = conn;
    }

    void DelConnection(int sockfd)
    {
        // 1.检查是否存在
        if (!ConnectionExist(sockfd))
            return;

        // 2._connnections删除
        _connections.erase(sockfd);

        // 3.内核中移除
        _epoller_ptr->DELEvent(sockfd);

        // 4.关闭sockfd
        close(sockfd);
    }

    void EnableWREvent(int sockfd, bool write, bool read)
    {
        // 1.检查是否存在
        if (!ConnectionExist(sockfd))
            return;
        // 注意别漏了EPOLLET
        uint32_t events = (EPOLLET | (write ? EPOLLOUT : 0) | (read ? EPOLLIN : 0));
        // 2.修改_connections内数据
        _connections[sockfd]->SetEvents(events);
        // 3.修改内核中数据
        _epoller_ptr->MODEvent(sockfd, events);
    }

    ~Reactor()
    {
    }

private:
    // epoll模型
    std::unique_ptr<Epoller> _epoller_ptr;
    // 存放fd与连接的映射
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;
    bool _isrunning;
    struct epoll_event _buff[BUFF_SIZE]; // 缓冲区，存放wait的结果
};